﻿using System;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;

namespace AvalonDock
{
    public class DocumentFloatingWindow : FloatingWindow
    {
        #region Constructors and Destructors

        static DocumentFloatingWindow()
        {
            //This OverrideMetadata call tells the system that this element wants to provide a style that is different than its base class.
            //This style is defined in themes\generic.xaml
            DefaultStyleKeyProperty.OverrideMetadata(
                typeof(DocumentFloatingWindow), new FrameworkPropertyMetadata(typeof(DocumentFloatingWindow)));

            ContentProperty.OverrideMetadata(
                typeof(DocumentFloatingWindow),
                new FrameworkPropertyMetadata(OnContentPropertyChanged, OnCoerceValueContentProperty));
        }

        internal DocumentFloatingWindow(DockingManager manager)
            : base(manager)
        {
        }

        #endregion

        #region Public Methods and Operators

        public override Pane ClonePane()
        {
            var paneToAnchor = new DocumentPane();

            ResizingPanel.SetEffectiveSize(paneToAnchor, new Size(Width, Height));

            //transfer contents from hosted pane in the floating window and
            //the new created dockable pane
            while (HostedPane.Items.Count > 0)
            {
                paneToAnchor.Items.Add(HostedPane.RemoveContent(0));
            }
            paneToAnchor.ApplyTemplate();

            return paneToAnchor;
        }

        public override void Dock()
        {
            ((DocumentContent)HostedPane.Items[0]).Show();

            base.Dock();
        }

        #endregion

        #region Methods

        internal override void OnEndDrag()
        {
            if (((FloatingDocumentPane)HostedPane).PreviousPane != null)
            {
                ((FloatingDocumentPane)HostedPane).PreviousPane.CheckContentsEmpty();
            }

            if (HostedPane.Items.Count == 0)
            {
                Close();
            }

            base.OnEndDrag();
        }

        internal override void OnHideSelectionBox()
        {
            Visibility = Visibility.Visible;
            base.OnHideSelectionBox();
        }

        internal override void OnShowSelectionBox()
        {
            Visibility = Visibility.Hidden;
            base.OnShowSelectionBox();
        }

        protected override void FilterMessage(object sender, FilterMessageEventArgs e)
        {
            e.Handled = false;

            if (Manager == null)
            {
                return;
            }

            switch (e.Msg)
            {
                case WM_NCLBUTTONDOWN: //Left button down on title -> start dragging over docking manager
                    if (e.WParam.ToInt32() == HTCAPTION)
                    {
                        var x = (short)((e.LParam.ToInt32() & 0xFFFF));
                        var y = (short)((e.LParam.ToInt32() >> 16));

                        Point clickPoint = this.TransformToDeviceDPI(new Point(x, y));
                        Manager.Drag(this, clickPoint, new Point(clickPoint.X - Left, clickPoint.Y - Top));

                        e.Handled = true;
                    }
                    break;
                case WM_NCLBUTTONDBLCLK: //Left Button Double Click -> Maximixe/Normal
                    if (e.WParam.ToInt32() == HTCAPTION)
                    {
                        WindowState = WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized;
                        e.Handled = true;
                    }
                    break;
            }

            base.FilterMessage(sender, e);
        }

        protected override bool OpenContextMenu(UIElement popupButton, Point ptMouse)
        {
            var cxMenu =
                FindResource(
                    new ComponentResourceKey(typeof(DockingManager), ContextMenuElement.DocumentFloatingWindow)) as
                ContextMenu;
            if (cxMenu != null)
            {
                foreach (MenuItem menuItem in cxMenu.Items.OfType<MenuItem>())
                {
                    menuItem.CommandTarget = HostedPane.SelectedItem as IInputElement;
                }

                if (popupButton != null)
                {
                    cxMenu.Placement = PlacementMode.Bottom;
                    cxMenu.PlacementTarget = popupButton;
                }
                else
                {
                    cxMenu.Placement = PlacementMode.Bottom;
                    cxMenu.PlacementRectangle = new Rect(ptMouse, new Size(0, 0));
                }

                cxMenu.IsOpen = true;
                return true;
            }

            return base.OpenContextMenu(popupButton, ptMouse);
        }

        private static object OnCoerceValueContentProperty(DependencyObject d, object baseValue)
        {
            var fl = ((DocumentFloatingWindow)d);

            if (fl.Content != null)
            {
                throw new InvalidOperationException("Content on floating windows can't be set more than one time.");
            }

            if (!(baseValue is DocumentContent))
            {
                throw new InvalidOperationException("Content must be of type DocumentContent");
            }

            var paneToReturn = new FloatingDocumentPane(fl, baseValue as DocumentContent);

            return paneToReturn;
        }

        private static void OnContentPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
        }

        #endregion
    }
}